interface NodeData {
    id: number;
    name: string;
    time: string;
    desc: string;
}

interface TextOptions {
    text: string;
    x: number;
    y: number;
    fontSize: number;
    color?: string;
    align?: 'left' | 'center' | 'right';
}

interface CircleOptions {
    x: number;
    y: number;
    radius: number;
    color?: string;
}

interface ArrowOptions {
    startX: number;
    startY: number;
    length: number;
    color?: string;
}

interface PositionArea {
    x: number;
    y: number;
    radius: number;
    nodeData: NodeData;
}

interface FlowChartConfig {
    nodeWidth: number;
    arrowWidth: number;
    firstNodeOffset: number;
    nodeSpacing: number;
    fontSize: {
        title: number;
        description: number;
        time: number;
    };
    colors: {
        text: string;
        node: string;
        arrow: string;
    };
    dimensions: {
        circleRadius: number;
        arrowHeight: number;
        arrowTipSize: number;
    };
}

export class useFlowChartRenderer {
    // 私有属性
    #canvas: HTMLCanvasElement | null = null;
    #ctx: CanvasRenderingContext2D | null = null;
    #currentIndex: number = 0;
    #totalNodes: number = 0;
    #renderData: NodeData[] = [];
    #PositionAreas: Map<number, PositionArea> = new Map();

    // 配置项
    config: FlowChartConfig = {
        nodeWidth: 160,
        arrowWidth: 100,
        firstNodeOffset: 20,
        nodeSpacing: 30,
        fontSize: {
            title: 18,
            description: 14,
            time: 12
        },
        colors: {
            text: '#333',
            node: '#4a90e2',
            arrow: '#ff6b6b'
        },
        dimensions: {
            circleRadius: 16,
            arrowHeight: 20,
            arrowTipSize: 30
        }
    };

    constructor(containerElement: HTMLElement) {
        if (!containerElement) {
            throw new Error('请提供外部盒子');
        }
        this.#initializeCanvas(containerElement);
    }

    /**
     * 初始化Canvas元素
     * @param container - 容器元素
     */
    #initializeCanvas(container: HTMLElement): void {
        this.#canvas = document.createElement("canvas");
        const rect = container.getBoundingClientRect();

        this.#setCanvasSize(rect.width, rect.height);
        this.#canvas.style.display = 'block';

        // 获取绘图上下文
        const ctx = this.#canvas.getContext("2d");
        if (!ctx) {
            throw new Error('无法获取Canvas上下文');
        }
        this.#ctx = ctx;

        // 清除画布
        this.#clearCanvas();

        container.appendChild(this.#canvas);
    }

    /**
     * 设置Canvas尺寸
     * @param width - 宽度
     * @param height - 高度
     */
    #setCanvasSize(width?: number, height?: number): void {
        if (!this.#canvas) return;
        
        const devicePixel = window.devicePixelRatio || 1;
        this.#canvas.width = (width || this.#canvas.width) * devicePixel;
        this.#canvas.height = (height || this.#canvas.height) * devicePixel;
        
        // 缩放画布以匹配设备像素比
        if (this.#ctx) {
            this.#ctx.scale(devicePixel, devicePixel);
        }
    }

    /**
     * 清除画布
     */
    #clearCanvas(): void {
        if (!this.#ctx || !this.#canvas) return;
        this.#ctx.clearRect(0, 0, this.#canvas.width, this.#canvas.height);
    }

    /**
     * 绘制流程组
     * @param nodeData - 节点数据
     */
    #drawNode(nodeData: NodeData): void {
        if (!nodeData || typeof nodeData !== 'object' || !this.#ctx || !this.#canvas) return;

        const ctx = this.#ctx;
        const { nodeWidth, arrowWidth, firstNodeOffset } = this.config;
        const { fontSize, colors, dimensions } = this.config;

        // 计算X坐标
        let x = (this.#currentIndex === 0)
            ? firstNodeOffset
            : (nodeWidth + arrowWidth) * this.#currentIndex + firstNodeOffset;

        // 基础Y坐标
        const baseY = this.#canvas.height * 0.2;

        // 绘制标题
        this.#drawText({
            text: nodeData.name.length > 8 ? nodeData.name.substring(0, 8).padEnd(10, ".") : nodeData.name,
            x: x + nodeWidth / 2,
            y: baseY,
            fontSize: fontSize.title,
            color: colors.text,
            align: 'center'
        });

        // 绘制圆形节点
        const circleY = baseY + this.#canvas.height * 0.25;
        this.#drawCircle({
            x: x + nodeWidth / 2,
            y: circleY,
            radius: dimensions.circleRadius,
            color: colors.node
        });
        
        // 记录节点位置信息
        this.#PositionAreas.set(nodeData.id, { 
            x: x + nodeWidth / 2, 
            y: circleY, 
            radius: dimensions.circleRadius, 
            nodeData 
        });

        // 绘制描述
        const descY = circleY + this.#canvas.height * 0.2;
        this.#drawText({
            text: nodeData.desc,
            x: x + nodeWidth / 2,
            y: descY,
            fontSize: fontSize.description,
            color: colors.text,
            align: 'center'
        });

        // 绘制时间
        const timeY = descY + this.#canvas.height * 0.15;
        this.#drawText({
            text: nodeData.time,
            x: x + nodeWidth / 2,
            y: timeY,
            fontSize: fontSize.time,
            color: colors.text,
            align: 'center'
        });

        // 如果不是最后一个节点，绘制箭头
        if (this.#currentIndex < this.#totalNodes - 1) {
            this.#drawArrow({
                startX: x + nodeWidth,
                startY: this.#canvas.height / 2,
                length: arrowWidth * 0.7,
                color: colors.arrow
            });
        }

        this.#currentIndex++;
    }

    /**
     * 绘制文本
     * @param options - 绘制选项
     */
    #drawText(options: TextOptions): void {
        if (!this.#ctx) return;
        
        const { text, x, y, fontSize, color, align = 'left' } = options;
        const ctx = this.#ctx;

        ctx.save();
        ctx.font = `${fontSize}px "Microsoft YaHei", sans-serif`;
        ctx.fillStyle = color || '#000';
        ctx.textAlign = align;
        ctx.textBaseline = 'middle';
        ctx.fillText(text, x, y);
        ctx.restore();
    }

    /**
     * 绘制圆形
     * @param options - 绘制选项
     */
    #drawCircle(options: CircleOptions): void {
        if (!this.#ctx) return;
        
        const { x, y, radius, color } = options;
        const ctx = this.#ctx;

        ctx.save();
        ctx.beginPath();
        ctx.fillStyle = color || '#000';
        ctx.arc(x, y, radius, 0, Math.PI * 2);
        ctx.fill();
        ctx.restore();
    }

    /**
     * 绘制箭头
     * @param options - 绘制选项
     */
    #drawArrow(options: ArrowOptions): void {
        if (!this.#ctx) return;
        
        const { startX, startY, length, color } = options;
        const { arrowHeight, arrowTipSize } = this.config.dimensions;
        const ctx = this.#ctx;

        ctx.save();
        ctx.fillStyle = color || '#000';

        // 绘制箭头主体
        ctx.beginPath();
        ctx.moveTo(startX, startY - arrowHeight / 2);
        ctx.lineTo(startX + length, startY - arrowHeight / 2);
        ctx.lineTo(startX + length, startY - arrowHeight);
        ctx.lineTo(startX + length + arrowTipSize, startY);
        ctx.lineTo(startX + length, startY + arrowHeight);
        ctx.lineTo(startX + length, startY + arrowHeight / 2);
        ctx.lineTo(startX, startY + arrowHeight / 2);
        ctx.closePath();
        ctx.fill();

        ctx.restore();
    }

    /**
     * 通过数据组获取宽
     * @param nodes - 节点数组
     */
    #calculateTotalWidth(nodes: NodeData[]): number {
        const { nodeWidth, arrowWidth, firstNodeOffset } = this.config;
        return (nodeWidth + firstNodeOffset) * (nodes.length - 1) + (arrowWidth) * (nodes.length);
    }

    /**
     * 设置流程数据并渲染
     * @param nodes - 节点数据数组
     */
    render(nodes: NodeData[]): void {
        if (!Array.isArray(nodes)) {
            throw new Error("请传递数组类型数据");
        }

        // 重置状态
        this.#currentIndex = 0;
        this.#totalNodes = nodes.length;
        this.#PositionAreas.clear();

        // 重新设置canvas的宽度
        this.#setCanvasSize(this.#calculateTotalWidth(nodes));
        // 保存目前渲染的数据
        this.#renderData = nodes;
        // 绘制所有节点
        nodes.forEach(node => this.#drawNode(node));
    }

    /**
     * 通过x,y坐标获取节点信息
     * @param x - 鼠标X坐标
     * @param y - 鼠标Y坐标
     */
    getCurrentClickNode(x: number, y: number): NodeData | null {
        if (!this.#canvas) return null;

        const rect = this.#canvas.getBoundingClientRect();
        const _x = x - rect.left;
        const _y = y - rect.top;

        // 通过圆的范围计算点击的节点目标
        for (const { x: nodeX, y: nodeY, radius, nodeData } of this.#PositionAreas.values()) {
            if (Math.pow(_x - nodeX, 2) + Math.pow(_y - nodeY, 2) < Math.pow(radius * 4, 2)) {
                return nodeData;
            }
        }
        return null;
    }

    /**
     * 销毁实例，清理资源
     */
    destroy(): void {
        if (this.#canvas && this.#canvas.parentNode) {
            this.#canvas.parentNode.removeChild(this.#canvas);
        }
        this.#canvas = null;
        this.#ctx = null;
        this.#currentIndex = 0;
        this.#PositionAreas.clear();
    }
}

// 使用示例
const container = document.querySelector('.flow-container') as HTMLElement;
if (container) {
    const flowChart = new useFlowChartRenderer(container);

    const flowData: NodeData[] = [
        {
            id: 1,
            name: "需求提出1",
            time: "2024.10.6",
            desc: "做保大队"
        },
        {
            id: 2,
            name: "需求审批2",
            time: "2024.10.7",
            desc: "孔灿"
        },
        {
            id: 3,
            name: "开发阶段3",
            time: "2024.10.8",
            desc: "技术团队"
        },
        {
            id: 4,
            name: "开发阶段4",
            time: "2024.10.8",
            desc: "技术团队"
        },
        {
            id: 5,
            name: "开发阶段1开发阶段1开发阶段1",
            time: "2024.10.8",
            desc: "技术团队"
        }
    ];

    flowChart.render(flowData);
    container.onmousedown = function (e: MouseEvent) {
        const node = flowChart.getCurrentClickNode(e.pageX, e.pageY);
        if (node) {
            console.log('点击的节点:', node);
            // 可以在这里添加点击后的处理逻辑
        }
    };
}